{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-05-27T03:49:57.717446Z",
     "start_time": "2019-05-27T03:49:57.684743Z"
    }
   },
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "import pickle\n",
    "from statsmodels.stats.outliers_influence import variance_inflation_factor\n",
    "import statsmodels.api as sm\n",
    "from sklearn import ensemble\n",
    "import matplotlib.pyplot as plt\n",
    "import seaborn as sns\n",
    "from sklearn.metrics import roc_auc_score\n",
    "from sklearn import datasets\n",
    "from sklearn.linear_model import LogisticRegression\n",
    "import os\n",
    "import pickle\n",
    "import copy"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-05-27T02:59:43.830411Z",
     "start_time": "2019-05-27T02:59:43.810484Z"
    }
   },
   "outputs": [],
   "source": [
    "data_01_list = \\\n",
    "    [[19,3,'Part Time',1],\n",
    "    [20,1,'Part Time',1],\n",
    "    [21,2,'Part Time',1],\n",
    "    [22,-1,'Part Time',1],\n",
    "    [23,0,'Part Time',1],\n",
    "    [24,5,'Part Time',0],\n",
    "    [25,1,'Part Time',1],\n",
    "    [26,2,'Part Time',1],\n",
    "    [27,1,'Full Time',1],\n",
    "    [28,2,'Full Time',0],\n",
    "    [29,1,'Full Time',0],\n",
    "    [30,2,'Full Time',0],\n",
    "    [33,6,'Full Time',1],\n",
    "    [34,5,'Full Time',0],\n",
    "    [35,6,'Part Time',0],\n",
    "    [36,5,'Part Time',0],\n",
    "    [37,6,'Full Time',0],\n",
    "    [38,5,'Full Time',0],\n",
    "    [48,4,'Full Time',1],\n",
    "    [49,3,'Others',1],\n",
    "    [50,4,'Full Time',0],\n",
    "    [51,3,'Others',0],\n",
    "    [52,4,'Others',0],\n",
    "    [53,3,'Others',0],\n",
    "    [56,-1,'Others',1],\n",
    "    [57,0,'Others',1],\n",
    "    [58,-1,'Others',1],\n",
    "    [59,0,'Others',1],\n",
    "    [60,-1,'Others',0],\n",
    "    [61,0,'Others',0]]\n",
    "    \n",
    "data_02_df = pd.DataFrame(data_01_list)\n",
    "data_02_df.columns = ['Age', 'TaCA', 'ES', 'y']\n",
    "data = data_02_df\n",
    "allFeatures = data.columns"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-05-27T02:59:43.863166Z",
     "start_time": "2019-05-27T02:59:43.832538Z"
    }
   },
   "outputs": [],
   "source": [
    "#计算变量分箱之后各分箱的坏样本率\n",
    "def BinBadRate(df, col, target, grantRateIndicator=0):\n",
    "    '''\n",
    "    :param df: 需要计算好坏比率的数据集\n",
    "    :param col: 需要计算好坏比率的特征\n",
    "    :param target: 好坏标签\n",
    "    :param grantRateIndicator: 1返回总体的坏样本率，0不返回\n",
    "    :return: 每箱的坏样本率，以及总体的坏样本率（当grantRateIndicator＝＝1时）\n",
    "    '''\n",
    "    #print(df.groupby([col])[target])\n",
    "    total = df.groupby([col])[target].count()\n",
    "    #print(total)\n",
    "    total = pd.DataFrame({'total': total})\n",
    "    #print(total)\n",
    "    bad = df.groupby([col])[target].sum()\n",
    "    bad = pd.DataFrame({'bad': bad})\n",
    "    #合并\n",
    "    regroup = total.merge(bad, left_index=True, right_index=True, how='left')\n",
    "    #print(regroup)\n",
    "    regroup.reset_index(level=0, inplace=True)\n",
    "    #print(regroup)\n",
    "    #计算坏样本率\n",
    "    regroup['bad_rate'] = regroup.apply(lambda x: x.bad * 1.0 / x.total, axis=1)\n",
    "    #print(regroup)\n",
    "    #生成字典，（变量名取值：坏样本率）\n",
    "    dicts = dict(zip(regroup[col],regroup['bad_rate']))\n",
    "    if grantRateIndicator==0:\n",
    "        return (dicts, regroup)\n",
    "    N = sum(regroup['total'])\n",
    "    B = sum(regroup['bad'])\n",
    "    #总体样本率\n",
    "    overallRate = B * 1.0 / N\n",
    "    return (dicts, regroup, overallRate)\n",
    "\n",
    "\n",
    "## 判断某变量的坏样本率是否单调\n",
    "def BadRateMonotone(df, sortByVar, target,special_attribute = []):\n",
    "    '''\n",
    "    :param df: 包含检验坏样本率的变量，和目标变量\n",
    "    :param sortByVar: 需要检验坏样本率的变量\n",
    "    :param target: 目标变量，0、1表示好、坏\n",
    "    :param special_attribute: 不参与检验的特殊值\n",
    "    :return: 坏样本率单调与否\n",
    "    '''\n",
    "    df2 = df.loc[~df[sortByVar].isin(special_attribute)]\n",
    "    if len(set(df2[sortByVar])) <= 2:\n",
    "        return True\n",
    "    regroup = BinBadRate(df2, sortByVar, target)[1]\n",
    "    combined = zip(regroup['total'],regroup['bad'])\n",
    "    badRate = [x[1]*1.0/x[0] for x in combined]\n",
    "    badRateNotMonotone = [badRate[i]<badRate[i+1] and badRate[i] < badRate[i-1] or badRate[i]>badRate[i+1] and badRate[i] > badRate[i-1]\n",
    "                          for i in range(1,len(badRate)-1)]\n",
    "    if True in badRateNotMonotone:\n",
    "        return False\n",
    "    else:\n",
    "        return True\n",
    "\n",
    "#计算WOE值\n",
    "def CalcWOE(df, col, target):\n",
    "    '''\n",
    "    :param df: 包含需要计算WOE的变量和目标变量\n",
    "    :param col: 需要计算WOE、IV的变量，必须是分箱后的变量，或者不需要分箱的类别型变量\n",
    "    :param target: 目标变量，0、1表示好、坏\n",
    "    :return: 返回WOE和IV\n",
    "    '''\n",
    "    total = df.groupby([col])[target].count()\n",
    "    total = pd.DataFrame({'total': total})\n",
    "    bad = df.groupby([col])[target].sum()\n",
    "    bad = pd.DataFrame({'bad': bad})\n",
    "    regroup = total.merge(bad, left_index=True, right_index=True, how='left')\n",
    "    regroup.reset_index(level=0, inplace=True)\n",
    "    N = sum(regroup['total'])\n",
    "    B = sum(regroup['bad'])\n",
    "    regroup['good'] = regroup['total'] - regroup['bad']\n",
    "    G = N - B\n",
    "    regroup['bad_pcnt'] = regroup['bad'].map(lambda x: x*1.0/B)\n",
    "    regroup['good_pcnt'] = regroup['good'].map(lambda x: x * 1.0 / G)\n",
    "    regroup['WOE'] = regroup.apply(lambda x: np.log(x.bad_pcnt*1.0/x.good_pcnt),axis = 1)\n",
    "    WOE_dict = regroup[[col,'WOE']].set_index(col).to_dict(orient='index')\n",
    "    for k, v in WOE_dict.items():\n",
    "        WOE_dict[k] = v['WOE']\n",
    "    IV = regroup.apply(lambda x: (x.good_pcnt-x.bad_pcnt)*np.log(x.good_pcnt*1.0/x.bad_pcnt),axis = 1)\n",
    "    IV = sum(IV)\n",
    "    return {\"WOE\": WOE_dict, 'IV':IV}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-05-27T02:59:43.885445Z",
     "start_time": "2019-05-27T02:59:43.865310Z"
    }
   },
   "outputs": [],
   "source": [
    "'''\n",
    "对类别型变量的分箱和WOE计算\n",
    "可以通过计算取值个数的方式判断是否是类别型变量\n",
    "'''\n",
    "#类别型变量\n",
    "categoricalFeatures = []\n",
    "#连续型变量\n",
    "numericalFeatures = []\n",
    "WOE_IV_dict = {}\n",
    "for var in allFeatures:\n",
    "    if len(set(data[var])) > 5:\n",
    "        numericalFeatures.append(var)\n",
    "    else:\n",
    "        categoricalFeatures.append(var)\n",
    "\n",
    "not_monotone =[]\n",
    "for var in categoricalFeatures:\n",
    "    #检查bad rate在箱中的单调性\n",
    "    if not BadRateMonotone(data, var, 'y'):\n",
    "        not_monotone.append(var)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-05-27T02:59:43.954198Z",
     "start_time": "2019-05-27T02:59:43.887817Z"
    }
   },
   "outputs": [],
   "source": [
    "'''\n",
    "连续型变量\n",
    "卡方分箱\n",
    "'''\n",
    "def AssignBin(x, cutOffPoints,special_attribute=[]):\n",
    "    '''\n",
    "    :param x: 某个变量的某个取值\n",
    "    :param cutOffPoints: 上述变量的分箱结果，用切分点表示\n",
    "    :param special_attribute:  不参与分箱的特殊取值\n",
    "    :return: 分箱后的对应的第几个箱，从0开始\n",
    "    for example, if cutOffPoints = [10,20,30], if x = 7, return Bin 0. If x = 35, return Bin 3\n",
    "    '''\n",
    "    numBin = len(cutOffPoints) + 1 + len(special_attribute)\n",
    "    if x in special_attribute:\n",
    "        i = special_attribute.index(x)+1\n",
    "        return 'Bin {}'.format(0-i)\n",
    "    if x<=cutOffPoints[0]:\n",
    "        return 'Bin 0'\n",
    "    elif x > cutOffPoints[-1]:\n",
    "        return 'Bin {}'.format(numBin-1)\n",
    "    else:\n",
    "        for i in range(0,numBin-1):\n",
    "            if cutOffPoints[i] < x <=  cutOffPoints[i+1]:\n",
    "                return 'Bin {}'.format(i+1)\n",
    "\n",
    "\n",
    "\n",
    "def AssignGroup(x, bin):\n",
    "    '''\n",
    "    :param x: 某个变量的某个取值\n",
    "    :param bin: 上述变量的分箱结果\n",
    "    :return: x在分箱结果下的映射\n",
    "    '''\n",
    "    N = len(bin)\n",
    "    if x<=min(bin):\n",
    "        return min(bin)\n",
    "    elif x>max(bin):\n",
    "        return 10e10\n",
    "    else:\n",
    "        for i in range(N-1):\n",
    "            if bin[i] < x <= bin[i+1]:\n",
    "                return bin[i+1]\n",
    " \n",
    " \n",
    "def SplitData(df, col, numOfSplit, special_attribute=[]):\n",
    "    '''\n",
    "    :param df: 按照col排序后的数据集\n",
    "    :param col: 待分箱的变量\n",
    "    :param numOfSplit: 切分的组别数\n",
    "    :param special_attribute: 在切分数据集的时候，某些特殊值需要排除在外\n",
    "    :return: 在原数据集上增加一列，把原始细粒度的col重新划分成粗粒度的值，便于分箱中的合并处理\n",
    "    '''\n",
    "    df2 = df.copy()\n",
    "    if special_attribute != []:\n",
    "        df2 = df.loc[~df[col].isin(special_attribute)]\n",
    "    N = df2.shape[0]#行数\n",
    "    #\" / \"就表示 浮点数除法，返回浮点结果;\" // \"表示整数除法\n",
    "    n = N//numOfSplit #每组样本数\n",
    "    splitPointIndex = [i*n for i in range(1,numOfSplit)] #分割点的下标\n",
    "    '''\n",
    "    [i*2 for i in range(1,100)]\n",
    "    [2, 4, 6, 8, 10,......,198]\n",
    "    '''\n",
    "    rawValues = sorted(list(df2[col])) #对取值进行排序\n",
    "    #取到粗糙卡方划分节点\n",
    "    splitPoint = [rawValues[i] for i in splitPointIndex] #分割点的取值\n",
    "    splitPoint = sorted(list(set(splitPoint)))\n",
    "    return splitPoint\n",
    "\n",
    "\n",
    "#计算卡方值的函数\n",
    "def Chi2(df, total_col, bad_col, overallRate):\n",
    "    '''\n",
    "    :param df: 包含全部样本总计与坏样本总计的数据框\n",
    "    :param total_col: 全部样本的个数\n",
    "    :param bad_col: 坏样本的个数\n",
    "    :param overallRate: 全体样本的坏样本占比\n",
    "    :return: 卡方值\n",
    "    '''\n",
    "    df2 = df.copy()\n",
    "    # 期望坏样本个数＝全部样本个数*平均坏样本占比\n",
    "    df2['expected'] = df[total_col].apply(lambda x: x*overallRate)\n",
    "    combined = zip(df2['expected'], df2[bad_col])\n",
    "    chi = [(i[0]-i[1])**2/i[0] for i in combined]\n",
    "    chi2 = sum(chi)\n",
    "    return chi2\n",
    "\n",
    "\n",
    "##ChiMerge_MaxInterval：通过指定最大间隔数，使用卡方值分割连续变量\n",
    "def ChiMerge(df, col, target, max_interval=5,special_attribute=[],minBinPcnt=0):\n",
    "    '''\n",
    "    :param df: 包含目标变量与分箱属性的数据框\n",
    "    :param col: 需要分箱的属性\n",
    "    :param target: 目标变量，取值0或1\n",
    "    :param max_interval: 最大分箱数。如果原始属性的取值个数低于该参数，不执行这段函数\n",
    "    :param special_attribute: 不参与分箱的属性取值，缺失值的情况\n",
    "    :param minBinPcnt：最小箱的占比，默认为0\n",
    "    :return: 分箱结果\n",
    "    '''\n",
    "    colLevels = sorted(list(set(df[col])))\n",
    "    N_distinct = len(colLevels)#不同的取值个数\n",
    "    if N_distinct <= max_interval:  #如果原始属性的取值个数低于max_interval，不执行这段函数\n",
    "        print (\"原始属性{}的取值个数低于max_interval\".format(col))\n",
    "        #分箱分数间隔段，少一个值也可以\n",
    "        #返回值colLevels会少一个最大值\n",
    "        return colLevels[:-1]\n",
    "    else:\n",
    "        if len(special_attribute)>=1:\n",
    "            #df1数据框取data_01中col那一列为特殊值的数据集\n",
    "            #df1 = df.loc[df[col].isin(special_attribute)]\n",
    "            print('{} 有缺失值的情况'.format(col))\n",
    "            #用逆函数对筛选后的结果取余，起删除指定行作用\n",
    "            df2 = df.loc[~df[col].isin(special_attribute)]\n",
    "        else:\n",
    "            df2 = df.copy()\n",
    "        N_distinct = len(list(set(df2[col])))#该特征不同的取值\n",
    " \n",
    "        # 步骤一: 通过col对数据集进行分组，求出每组的总样本数与坏样本数\n",
    "        if N_distinct > 100:\n",
    "            '''\n",
    "            split_x样例\n",
    "            [2, 8, 9.3, 10, 30,......,1800]\n",
    "            '''\n",
    "            split_x = SplitData(df2, col, 100)\n",
    "            #把值变为划分点的值\n",
    "            df2['temp'] = df2[col].map(lambda x: AssignGroup(x, split_x))\n",
    "        else:\n",
    "            #假如数值取值小于100就不发生变化了\n",
    "            df2['temp'] = df2[col]\n",
    "        # 总体bad rate将被用来计算expected bad count\n",
    "        (binBadRate, regroup, overallRate) = BinBadRate(df2, 'temp', target, grantRateIndicator=1)\n",
    " \n",
    "        # 首先，每个单独的属性值将被分为单独的一组\n",
    "        # 对属性值进行排序，然后两两组别进行合并\n",
    "        colLevels = sorted(list(set(df2['temp'])))\n",
    "        groupIntervals = [[i] for i in colLevels]\n",
    " \n",
    "        # 步骤二：建立循环，不断合并最优的相邻两个组别，直到：\n",
    "        # 1，最终分裂出来的分箱数<＝预设的最大分箱数\n",
    "        # 2，每箱的占比不低于预设值（可选）\n",
    "        # 3，每箱同时包含好坏样本\n",
    "        # 如果有特殊属性，那么最终分裂出来的分箱数＝预设的最大分箱数－特殊属性的个数\n",
    "        split_intervals = max_interval - len(special_attribute)\n",
    "        while (len(groupIntervals) > split_intervals):  # 终止条件: 当前分箱数＝预设的分箱数\n",
    "            # 每次循环时, 计算合并相邻组别后的卡方值。具有最小卡方值的合并方案，是最优方案\n",
    "            #存储卡方值\n",
    "            chisqList = []\n",
    "            for k in range(len(groupIntervals)-1):\n",
    "                temp_group = groupIntervals[k] + groupIntervals[k+1]\n",
    "                df2b = regroup.loc[regroup['temp'].isin(temp_group)]\n",
    "                chisq = Chi2(df2b, 'total', 'bad', overallRate)\n",
    "                chisqList.append(chisq)\n",
    "            best_comnbined = chisqList.index(min(chisqList))\n",
    "            groupIntervals[best_comnbined] = groupIntervals[best_comnbined] + groupIntervals[best_comnbined+1]\n",
    "            # after combining two intervals, we need to remove one of them\n",
    "            groupIntervals.remove(groupIntervals[best_comnbined+1])\n",
    "        groupIntervals = [sorted(i) for i in groupIntervals]\n",
    "        cutOffPoints = [max(i) for i in groupIntervals[:-1]]\n",
    " \n",
    "        # 检查是否有箱没有好或者坏样本。如果有，需要跟相邻的箱进行合并，直到每箱同时包含好坏样本\n",
    "        groupedvalues = df2['temp'].apply(lambda x: AssignBin(x, cutOffPoints))\n",
    "        #已成完成卡方分箱，但是没有考虑其单调性\n",
    "        df2['temp_Bin'] = groupedvalues\n",
    "        (binBadRate,regroup) = BinBadRate(df2, 'temp_Bin', target)\n",
    "        [minBadRate, maxBadRate] = [min(binBadRate.values()),max(binBadRate.values())]\n",
    "        while minBadRate ==0 or maxBadRate == 1:\n",
    "            # 找出全部为好／坏样本的箱\n",
    "            indexForBad01 = regroup[regroup['bad_rate'].isin([0,1])].temp_Bin.tolist()\n",
    "            bin=indexForBad01[0]\n",
    "            # 如果是最后一箱，则需要和上一个箱进行合并，也就意味着分裂点cutOffPoints中的最后一个需要移除\n",
    "            if bin == max(regroup.temp_Bin):\n",
    "                cutOffPoints = cutOffPoints[:-1]\n",
    "            # 如果是第一箱，则需要和下一个箱进行合并，也就意味着分裂点cutOffPoints中的第一个需要移除\n",
    "            elif bin == min(regroup.temp_Bin):\n",
    "                cutOffPoints = cutOffPoints[1:]\n",
    "            # 如果是中间的某一箱，则需要和前后中的一个箱进行合并，依据是较小的卡方值\n",
    "            else:\n",
    "                # 和前一箱进行合并，并且计算卡方值\n",
    "                currentIndex = list(regroup.temp_Bin).index(bin)\n",
    "                prevIndex = list(regroup.temp_Bin)[currentIndex - 1]\n",
    "                df3 = df2.loc[df2['temp_Bin'].isin([prevIndex, bin])]\n",
    "                (binBadRate, df2b) = BinBadRate(df3, 'temp_Bin', target)\n",
    "                chisq1 = Chi2(df2b, 'total', 'bad', overallRate)\n",
    "                # 和后一箱进行合并，并且计算卡方值\n",
    "                laterIndex = list(regroup.temp_Bin)[currentIndex + 1]\n",
    "                df3b = df2.loc[df2['temp_Bin'].isin([laterIndex, bin])]\n",
    "                (binBadRate, df2b) = BinBadRate(df3b, 'temp_Bin', target)\n",
    "                chisq2 = Chi2(df2b, 'total', 'bad', overallRate)\n",
    "                if chisq1 < chisq2:\n",
    "                    cutOffPoints.remove(cutOffPoints[currentIndex - 1])\n",
    "                else:\n",
    "                    cutOffPoints.remove(cutOffPoints[currentIndex])\n",
    "            # 完成合并之后，需要再次计算新的分箱准则下，每箱是否同时包含好坏样本\n",
    "            groupedvalues = df2['temp'].apply(lambda x: AssignBin(x, cutOffPoints))\n",
    "            df2['temp_Bin'] = groupedvalues\n",
    "            (binBadRate, regroup) = BinBadRate(df2, 'temp_Bin', target)\n",
    "            [minBadRate, maxBadRate] = [min(binBadRate.values()), max(binBadRate.values())]\n",
    " \n",
    "        # 需要检查分箱后的最小占比\n",
    "        if minBinPcnt > 0:\n",
    "            groupedvalues = df2['temp'].apply(lambda x: AssignBin(x, cutOffPoints))\n",
    "            df2['temp_Bin'] = groupedvalues\n",
    "            #value_counts每个数值出现了多少次\n",
    "            valueCounts = groupedvalues.value_counts().to_frame()\n",
    "            N=sum(valueCounts['temp'])\n",
    "            valueCounts['pcnt'] = valueCounts['temp'].apply(lambda x: x * 1.0 / N)\n",
    "            valueCounts = valueCounts.sort_index()\n",
    "            minPcnt = min(valueCounts['pcnt'])\n",
    "            #一定要箱数大于2才可以，要不就不能再合并了\n",
    "            while minPcnt < minBinPcnt and len(cutOffPoints) > 2:\n",
    "                # 找出占比最小的箱\n",
    "                indexForMinPcnt = valueCounts[valueCounts['pcnt'] == minPcnt].index.tolist()[0]\n",
    "                # 如果占比最小的箱是最后一箱，则需要和上一个箱进行合并，也就意味着分裂点cutOffPoints中的最后一个需要移除\n",
    "                if indexForMinPcnt == max(valueCounts.index):\n",
    "                    cutOffPoints = cutOffPoints[:-1]\n",
    "                # 如果占比最小的箱是第一箱，则需要和下一个箱进行合并，也就意味着分裂点cutOffPoints中的第一个需要移除\n",
    "                elif indexForMinPcnt == min(valueCounts.index):\n",
    "                    cutOffPoints = cutOffPoints[1:]\n",
    "                # 如果占比最小的箱是中间的某一箱，则需要和前后中的一个箱进行合并，依据是较小的卡方值\n",
    "                else:\n",
    "                    # 和前一箱进行合并，并且计算卡方值\n",
    "                    currentIndex = list(valueCounts.index).index(indexForMinPcnt)\n",
    "                    prevIndex = list(valueCounts.index)[currentIndex - 1]\n",
    "                    df3 = df2.loc[df2['temp_Bin'].isin([prevIndex, indexForMinPcnt])]\n",
    "                    (binBadRate, df2b) = BinBadRate(df3, 'temp_Bin', target)\n",
    "                    chisq1 = Chi2(df2b, 'total', 'bad', overallRate)\n",
    "                    # 和后一箱进行合并，并且计算卡方值\n",
    "                    laterIndex = list(valueCounts.index)[currentIndex + 1]\n",
    "                    df3b = df2.loc[df2['temp_Bin'].isin([laterIndex, indexForMinPcnt])]\n",
    "                    (binBadRate, df2b) = BinBadRate(df3b, 'temp_Bin', target)\n",
    "                    chisq2 = Chi2(df2b, 'total', 'bad', overallRate)\n",
    "                    if chisq1 < chisq2:\n",
    "                        cutOffPoints.remove(cutOffPoints[currentIndex - 1])\n",
    "                    else:\n",
    "                        cutOffPoints.remove(cutOffPoints[currentIndex])\n",
    "        cutOffPoints = special_attribute + cutOffPoints\n",
    "        return cutOffPoints\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-05-27T02:59:45.179562Z",
     "start_time": "2019-05-27T02:59:43.956345Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "********* 分箱结果（分割点）************\n",
      "[{'Age': [26, 30, 36, 53]}, {'TaCA': [0, 5]}]\n"
     ]
    }
   ],
   "source": [
    "'''\n",
    "对于数值型变量，需要先分箱，再计算WOE、IV\n",
    "分箱的结果需要满足：\n",
    "1，箱数不超过5\n",
    "2，bad rate单调\n",
    "3，每箱占比不低于5%\n",
    "'''\n",
    "binNums = {'Age':5, 'TaCA':3}\n",
    "bin_dict = []\n",
    "for var in numericalFeatures:\n",
    "    binNum = binNums[var]+1\n",
    "    newBin = var + '_Bin'\n",
    "    bin = ChiMerge(data, var, 'y',max_interval=binNum,minBinPcnt = 0.05)\n",
    "    data[newBin] = data[var].apply(lambda x: AssignBin(x,bin))\n",
    "    # 如果不满足单调性，就降低分箱个数\n",
    "    while not BadRateMonotone(data, newBin, 'y'):\n",
    "        binNum -= 1\n",
    "        bin = ChiMerge(data, var, 'y', max_interval=binNum, minBinPcnt=0.05)\n",
    "        data[newBin] = data[var].apply(lambda x: AssignBin(x, bin))\n",
    "    WOE_IV_dict[newBin] = CalcWOE(data, newBin, 'y')\n",
    "    bin_dict.append({var:bin})\n",
    "print('********* 分箱结果（分割点）************')\n",
    "print(bin_dict)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-05-27T03:24:15.330279Z",
     "start_time": "2019-05-27T03:24:15.299111Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Age</th>\n",
       "      <th>TaCA</th>\n",
       "      <th>ES</th>\n",
       "      <th>y</th>\n",
       "      <th>Age_Bin</th>\n",
       "      <th>TaCA_Bin</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>19</td>\n",
       "      <td>3</td>\n",
       "      <td>Part Time</td>\n",
       "      <td>1</td>\n",
       "      <td>Age1_[-inf, 26)</td>\n",
       "      <td>TaCA2_[0, 5)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>20</td>\n",
       "      <td>1</td>\n",
       "      <td>Part Time</td>\n",
       "      <td>1</td>\n",
       "      <td>Age1_[-inf, 26)</td>\n",
       "      <td>TaCA2_[0, 5)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>21</td>\n",
       "      <td>2</td>\n",
       "      <td>Part Time</td>\n",
       "      <td>1</td>\n",
       "      <td>Age1_[-inf, 26)</td>\n",
       "      <td>TaCA2_[0, 5)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>22</td>\n",
       "      <td>-1</td>\n",
       "      <td>Part Time</td>\n",
       "      <td>1</td>\n",
       "      <td>Age1_[-inf, 26)</td>\n",
       "      <td>TaCA1_[-inf, 0)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>23</td>\n",
       "      <td>0</td>\n",
       "      <td>Part Time</td>\n",
       "      <td>1</td>\n",
       "      <td>Age1_[-inf, 26)</td>\n",
       "      <td>TaCA2_[0, 5)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>24</td>\n",
       "      <td>5</td>\n",
       "      <td>Part Time</td>\n",
       "      <td>0</td>\n",
       "      <td>Age1_[-inf, 26)</td>\n",
       "      <td>TaCA3_[5, inf)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>25</td>\n",
       "      <td>1</td>\n",
       "      <td>Part Time</td>\n",
       "      <td>1</td>\n",
       "      <td>Age1_[-inf, 26)</td>\n",
       "      <td>TaCA2_[0, 5)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>26</td>\n",
       "      <td>2</td>\n",
       "      <td>Part Time</td>\n",
       "      <td>1</td>\n",
       "      <td>Age2_[26, 30)</td>\n",
       "      <td>TaCA2_[0, 5)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>27</td>\n",
       "      <td>1</td>\n",
       "      <td>Full Time</td>\n",
       "      <td>1</td>\n",
       "      <td>Age2_[26, 30)</td>\n",
       "      <td>TaCA2_[0, 5)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>28</td>\n",
       "      <td>2</td>\n",
       "      <td>Full Time</td>\n",
       "      <td>0</td>\n",
       "      <td>Age2_[26, 30)</td>\n",
       "      <td>TaCA2_[0, 5)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>10</th>\n",
       "      <td>29</td>\n",
       "      <td>1</td>\n",
       "      <td>Full Time</td>\n",
       "      <td>0</td>\n",
       "      <td>Age2_[26, 30)</td>\n",
       "      <td>TaCA2_[0, 5)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>11</th>\n",
       "      <td>30</td>\n",
       "      <td>2</td>\n",
       "      <td>Full Time</td>\n",
       "      <td>0</td>\n",
       "      <td>Age3_[30, 36)</td>\n",
       "      <td>TaCA2_[0, 5)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>12</th>\n",
       "      <td>33</td>\n",
       "      <td>6</td>\n",
       "      <td>Full Time</td>\n",
       "      <td>1</td>\n",
       "      <td>Age3_[30, 36)</td>\n",
       "      <td>TaCA3_[5, inf)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>13</th>\n",
       "      <td>34</td>\n",
       "      <td>5</td>\n",
       "      <td>Full Time</td>\n",
       "      <td>0</td>\n",
       "      <td>Age3_[30, 36)</td>\n",
       "      <td>TaCA3_[5, inf)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>14</th>\n",
       "      <td>35</td>\n",
       "      <td>6</td>\n",
       "      <td>Part Time</td>\n",
       "      <td>0</td>\n",
       "      <td>Age3_[30, 36)</td>\n",
       "      <td>TaCA3_[5, inf)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>15</th>\n",
       "      <td>36</td>\n",
       "      <td>5</td>\n",
       "      <td>Part Time</td>\n",
       "      <td>0</td>\n",
       "      <td>Age4_[36, 53)</td>\n",
       "      <td>TaCA3_[5, inf)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>16</th>\n",
       "      <td>37</td>\n",
       "      <td>6</td>\n",
       "      <td>Full Time</td>\n",
       "      <td>0</td>\n",
       "      <td>Age4_[36, 53)</td>\n",
       "      <td>TaCA3_[5, inf)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>17</th>\n",
       "      <td>38</td>\n",
       "      <td>5</td>\n",
       "      <td>Full Time</td>\n",
       "      <td>0</td>\n",
       "      <td>Age4_[36, 53)</td>\n",
       "      <td>TaCA3_[5, inf)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>18</th>\n",
       "      <td>48</td>\n",
       "      <td>4</td>\n",
       "      <td>Full Time</td>\n",
       "      <td>1</td>\n",
       "      <td>Age4_[36, 53)</td>\n",
       "      <td>TaCA2_[0, 5)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19</th>\n",
       "      <td>49</td>\n",
       "      <td>3</td>\n",
       "      <td>Others</td>\n",
       "      <td>1</td>\n",
       "      <td>Age4_[36, 53)</td>\n",
       "      <td>TaCA2_[0, 5)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>20</th>\n",
       "      <td>50</td>\n",
       "      <td>4</td>\n",
       "      <td>Full Time</td>\n",
       "      <td>0</td>\n",
       "      <td>Age4_[36, 53)</td>\n",
       "      <td>TaCA2_[0, 5)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>21</th>\n",
       "      <td>51</td>\n",
       "      <td>3</td>\n",
       "      <td>Others</td>\n",
       "      <td>0</td>\n",
       "      <td>Age4_[36, 53)</td>\n",
       "      <td>TaCA2_[0, 5)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>22</th>\n",
       "      <td>52</td>\n",
       "      <td>4</td>\n",
       "      <td>Others</td>\n",
       "      <td>0</td>\n",
       "      <td>Age4_[36, 53)</td>\n",
       "      <td>TaCA2_[0, 5)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>23</th>\n",
       "      <td>53</td>\n",
       "      <td>3</td>\n",
       "      <td>Others</td>\n",
       "      <td>0</td>\n",
       "      <td>Age5_[53, inf)</td>\n",
       "      <td>TaCA2_[0, 5)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>24</th>\n",
       "      <td>56</td>\n",
       "      <td>-1</td>\n",
       "      <td>Others</td>\n",
       "      <td>1</td>\n",
       "      <td>Age5_[53, inf)</td>\n",
       "      <td>TaCA1_[-inf, 0)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>25</th>\n",
       "      <td>57</td>\n",
       "      <td>0</td>\n",
       "      <td>Others</td>\n",
       "      <td>1</td>\n",
       "      <td>Age5_[53, inf)</td>\n",
       "      <td>TaCA2_[0, 5)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>26</th>\n",
       "      <td>58</td>\n",
       "      <td>-1</td>\n",
       "      <td>Others</td>\n",
       "      <td>1</td>\n",
       "      <td>Age5_[53, inf)</td>\n",
       "      <td>TaCA1_[-inf, 0)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>27</th>\n",
       "      <td>59</td>\n",
       "      <td>0</td>\n",
       "      <td>Others</td>\n",
       "      <td>1</td>\n",
       "      <td>Age5_[53, inf)</td>\n",
       "      <td>TaCA2_[0, 5)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>28</th>\n",
       "      <td>60</td>\n",
       "      <td>-1</td>\n",
       "      <td>Others</td>\n",
       "      <td>0</td>\n",
       "      <td>Age5_[53, inf)</td>\n",
       "      <td>TaCA1_[-inf, 0)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>29</th>\n",
       "      <td>61</td>\n",
       "      <td>0</td>\n",
       "      <td>Others</td>\n",
       "      <td>0</td>\n",
       "      <td>Age5_[53, inf)</td>\n",
       "      <td>TaCA2_[0, 5)</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "    Age  TaCA         ES  y          Age_Bin         TaCA_Bin\n",
       "0    19     3  Part Time  1  Age1_[-inf, 26)     TaCA2_[0, 5)\n",
       "1    20     1  Part Time  1  Age1_[-inf, 26)     TaCA2_[0, 5)\n",
       "2    21     2  Part Time  1  Age1_[-inf, 26)     TaCA2_[0, 5)\n",
       "3    22    -1  Part Time  1  Age1_[-inf, 26)  TaCA1_[-inf, 0)\n",
       "4    23     0  Part Time  1  Age1_[-inf, 26)     TaCA2_[0, 5)\n",
       "5    24     5  Part Time  0  Age1_[-inf, 26)   TaCA3_[5, inf)\n",
       "6    25     1  Part Time  1  Age1_[-inf, 26)     TaCA2_[0, 5)\n",
       "7    26     2  Part Time  1    Age2_[26, 30)     TaCA2_[0, 5)\n",
       "8    27     1  Full Time  1    Age2_[26, 30)     TaCA2_[0, 5)\n",
       "9    28     2  Full Time  0    Age2_[26, 30)     TaCA2_[0, 5)\n",
       "10   29     1  Full Time  0    Age2_[26, 30)     TaCA2_[0, 5)\n",
       "11   30     2  Full Time  0    Age3_[30, 36)     TaCA2_[0, 5)\n",
       "12   33     6  Full Time  1    Age3_[30, 36)   TaCA3_[5, inf)\n",
       "13   34     5  Full Time  0    Age3_[30, 36)   TaCA3_[5, inf)\n",
       "14   35     6  Part Time  0    Age3_[30, 36)   TaCA3_[5, inf)\n",
       "15   36     5  Part Time  0    Age4_[36, 53)   TaCA3_[5, inf)\n",
       "16   37     6  Full Time  0    Age4_[36, 53)   TaCA3_[5, inf)\n",
       "17   38     5  Full Time  0    Age4_[36, 53)   TaCA3_[5, inf)\n",
       "18   48     4  Full Time  1    Age4_[36, 53)     TaCA2_[0, 5)\n",
       "19   49     3     Others  1    Age4_[36, 53)     TaCA2_[0, 5)\n",
       "20   50     4  Full Time  0    Age4_[36, 53)     TaCA2_[0, 5)\n",
       "21   51     3     Others  0    Age4_[36, 53)     TaCA2_[0, 5)\n",
       "22   52     4     Others  0    Age4_[36, 53)     TaCA2_[0, 5)\n",
       "23   53     3     Others  0   Age5_[53, inf)     TaCA2_[0, 5)\n",
       "24   56    -1     Others  1   Age5_[53, inf)  TaCA1_[-inf, 0)\n",
       "25   57     0     Others  1   Age5_[53, inf)     TaCA2_[0, 5)\n",
       "26   58    -1     Others  1   Age5_[53, inf)  TaCA1_[-inf, 0)\n",
       "27   59     0     Others  1   Age5_[53, inf)     TaCA2_[0, 5)\n",
       "28   60    -1     Others  0   Age5_[53, inf)  TaCA1_[-inf, 0)\n",
       "29   61     0     Others  0   Age5_[53, inf)     TaCA2_[0, 5)"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def value2bin(x,cutoffs,col):    \n",
    "    '''\n",
    "    将变量的值转换成相应的组。\n",
    "    x: 需要转换到分组的值\n",
    "    cutoffs: 各组的起始值。\n",
    "    col: 需要分组的列名\n",
    "    return: x对应的组，如group1。从group1开始。\n",
    "    '''    \n",
    "    #切分点从小到大排序。\n",
    "    cutoffs = sorted(cutoffs)\n",
    "    num_bins = len(cutoffs)    \n",
    "    #异常情况：小于第一组的起始值。这里直接放到第一组。    \n",
    "    #异常值建议在分组之前先处理妥善。\n",
    "    cutoffs = [float('-inf')] + cutoffs + [np.inf]\n",
    "    for i in range(1, len(cutoffs)):\n",
    "        if cutoffs[i-1] <= x < cutoffs[i]:            \n",
    "            return '%s%s_[%s, %s)' % (col, i, cutoffs[i-1], cutoffs[i]) \n",
    "\n",
    "for bin_d in bin_dict:\n",
    "    col = list(bin_d.keys())[0]\n",
    "    cutoffs = bin_d[col]\n",
    "    data[col+'_Bin'] = data[col].apply(value2bin,args=(cutoffs,col))\n",
    "data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-05-27T03:24:43.207823Z",
     "start_time": "2019-05-27T03:24:43.132700Z"
    },
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>index</th>\n",
       "      <th>WOE</th>\n",
       "      <th>IV</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>Age1_[-inf, 26)</td>\n",
       "      <td>1.791759</td>\n",
       "      <td>1.055877</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>Age2_[26, 30)</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>1.055877</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>Age3_[30, 36)</td>\n",
       "      <td>-1.098612</td>\n",
       "      <td>1.055877</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>Age4_[36, 53)</td>\n",
       "      <td>-1.098612</td>\n",
       "      <td>1.055877</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>Age5_[53, inf)</td>\n",
       "      <td>0.287682</td>\n",
       "      <td>1.055877</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>TaCA1_[-inf, 0)</td>\n",
       "      <td>1.098612</td>\n",
       "      <td>0.807426</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>TaCA2_[0, 5)</td>\n",
       "      <td>0.318454</td>\n",
       "      <td>0.807426</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>TaCA3_[5, inf)</td>\n",
       "      <td>-1.791759</td>\n",
       "      <td>0.807426</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>Full Time</td>\n",
       "      <td>-0.847298</td>\n",
       "      <td>0.451892</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>Others</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.451892</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>10</th>\n",
       "      <td>Part Time</td>\n",
       "      <td>0.847298</td>\n",
       "      <td>0.451892</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "              index       WOE        IV\n",
       "0   Age1_[-inf, 26)  1.791759  1.055877\n",
       "1     Age2_[26, 30)  0.000000  1.055877\n",
       "2     Age3_[30, 36) -1.098612  1.055877\n",
       "3     Age4_[36, 53) -1.098612  1.055877\n",
       "4    Age5_[53, inf)  0.287682  1.055877\n",
       "5   TaCA1_[-inf, 0)  1.098612  0.807426\n",
       "6      TaCA2_[0, 5)  0.318454  0.807426\n",
       "7    TaCA3_[5, inf) -1.791759  0.807426\n",
       "8         Full Time -0.847298  0.451892\n",
       "9            Others  0.000000  0.451892\n",
       "10        Part Time  0.847298  0.451892"
      ]
     },
     "execution_count": 42,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# import pdb\n",
    "# pdb.set_trace()\n",
    "df_woe = pd.DataFrame()\n",
    "for col in ['Age_Bin', 'TaCA_Bin', 'ES']:\n",
    "    df_woe = pd.concat([df_woe, pd.DataFrame(CalcWOE(data, col, 'y'))])\n",
    "df_woe = df_woe.reset_index()\n",
    "df_woe"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-05-27T03:14:17.461682Z",
     "start_time": "2019-05-27T03:14:17.447315Z"
    }
   },
   "outputs": [],
   "source": [
    "### 计算KS值\n",
    "def KS(df, score, target):\n",
    "    '''\n",
    "    :param df: 包含目标变量与预测值的数据集,dataframe\n",
    "    :param score: 得分或者概率,str\n",
    "    :param target: 目标变量,str\n",
    "    :return: KS值\n",
    "    '''\n",
    "    total = df.groupby([score])[target].count()\n",
    "    bad = df.groupby([score])[target].sum()\n",
    "    all = pd.DataFrame({'total':total, 'bad':bad})\n",
    "    all.index.name = 'a'\n",
    "    # print(all)\n",
    "    all['good'] = all['total'] - all['bad']\n",
    "    all[score] = all.index\n",
    "    # print(all)\n",
    "    all = all.sort_values(by=score,ascending=False)\n",
    "    all.index = range(len(all))\n",
    "    all['badCumRate'] = all['bad'].cumsum() / all['bad'].sum()\n",
    "    all['goodCumRate'] = all['good'].cumsum() / all['good'].sum()\n",
    "    KS = all.apply(lambda x: x.badCumRate - x.goodCumRate, axis=1)\n",
    "    return max(KS)\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-05-27T03:52:17.977487Z",
     "start_time": "2019-05-27T03:52:17.885069Z"
    },
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Age_Bin_WOE</th>\n",
       "      <th>TaCA_Bin_WOE</th>\n",
       "      <th>ES_WOE</th>\n",
       "      <th>y</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>1.791759</td>\n",
       "      <td>0.318454</td>\n",
       "      <td>0.847298</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>1.791759</td>\n",
       "      <td>0.318454</td>\n",
       "      <td>0.847298</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>1.791759</td>\n",
       "      <td>0.318454</td>\n",
       "      <td>0.847298</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>1.791759</td>\n",
       "      <td>1.098612</td>\n",
       "      <td>0.847298</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>1.791759</td>\n",
       "      <td>0.318454</td>\n",
       "      <td>0.847298</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>1.791759</td>\n",
       "      <td>-1.791759</td>\n",
       "      <td>0.847298</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>1.791759</td>\n",
       "      <td>0.318454</td>\n",
       "      <td>0.847298</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.318454</td>\n",
       "      <td>0.847298</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.318454</td>\n",
       "      <td>-0.847298</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.318454</td>\n",
       "      <td>-0.847298</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>10</th>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.318454</td>\n",
       "      <td>-0.847298</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>11</th>\n",
       "      <td>-1.098612</td>\n",
       "      <td>0.318454</td>\n",
       "      <td>-0.847298</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>12</th>\n",
       "      <td>-1.098612</td>\n",
       "      <td>-1.791759</td>\n",
       "      <td>-0.847298</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>13</th>\n",
       "      <td>-1.098612</td>\n",
       "      <td>-1.791759</td>\n",
       "      <td>-0.847298</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>14</th>\n",
       "      <td>-1.098612</td>\n",
       "      <td>-1.791759</td>\n",
       "      <td>0.847298</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>15</th>\n",
       "      <td>-1.098612</td>\n",
       "      <td>-1.791759</td>\n",
       "      <td>0.847298</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>16</th>\n",
       "      <td>-1.098612</td>\n",
       "      <td>-1.791759</td>\n",
       "      <td>-0.847298</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>17</th>\n",
       "      <td>-1.098612</td>\n",
       "      <td>-1.791759</td>\n",
       "      <td>-0.847298</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>18</th>\n",
       "      <td>-1.098612</td>\n",
       "      <td>0.318454</td>\n",
       "      <td>-0.847298</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19</th>\n",
       "      <td>-1.098612</td>\n",
       "      <td>0.318454</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>20</th>\n",
       "      <td>-1.098612</td>\n",
       "      <td>0.318454</td>\n",
       "      <td>-0.847298</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>21</th>\n",
       "      <td>-1.098612</td>\n",
       "      <td>0.318454</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>22</th>\n",
       "      <td>-1.098612</td>\n",
       "      <td>0.318454</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>23</th>\n",
       "      <td>0.287682</td>\n",
       "      <td>0.318454</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>24</th>\n",
       "      <td>0.287682</td>\n",
       "      <td>1.098612</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>25</th>\n",
       "      <td>0.287682</td>\n",
       "      <td>0.318454</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>26</th>\n",
       "      <td>0.287682</td>\n",
       "      <td>1.098612</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>27</th>\n",
       "      <td>0.287682</td>\n",
       "      <td>0.318454</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>28</th>\n",
       "      <td>0.287682</td>\n",
       "      <td>1.098612</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>29</th>\n",
       "      <td>0.287682</td>\n",
       "      <td>0.318454</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "    Age_Bin_WOE  TaCA_Bin_WOE    ES_WOE  y\n",
       "0      1.791759      0.318454  0.847298  1\n",
       "1      1.791759      0.318454  0.847298  1\n",
       "2      1.791759      0.318454  0.847298  1\n",
       "3      1.791759      1.098612  0.847298  1\n",
       "4      1.791759      0.318454  0.847298  1\n",
       "5      1.791759     -1.791759  0.847298  0\n",
       "6      1.791759      0.318454  0.847298  1\n",
       "7      0.000000      0.318454  0.847298  1\n",
       "8      0.000000      0.318454 -0.847298  1\n",
       "9      0.000000      0.318454 -0.847298  0\n",
       "10     0.000000      0.318454 -0.847298  0\n",
       "11    -1.098612      0.318454 -0.847298  0\n",
       "12    -1.098612     -1.791759 -0.847298  1\n",
       "13    -1.098612     -1.791759 -0.847298  0\n",
       "14    -1.098612     -1.791759  0.847298  0\n",
       "15    -1.098612     -1.791759  0.847298  0\n",
       "16    -1.098612     -1.791759 -0.847298  0\n",
       "17    -1.098612     -1.791759 -0.847298  0\n",
       "18    -1.098612      0.318454 -0.847298  1\n",
       "19    -1.098612      0.318454  0.000000  1\n",
       "20    -1.098612      0.318454 -0.847298  0\n",
       "21    -1.098612      0.318454  0.000000  0\n",
       "22    -1.098612      0.318454  0.000000  0\n",
       "23     0.287682      0.318454  0.000000  0\n",
       "24     0.287682      1.098612  0.000000  1\n",
       "25     0.287682      0.318454  0.000000  1\n",
       "26     0.287682      1.098612  0.000000  1\n",
       "27     0.287682      0.318454  0.000000  1\n",
       "28     0.287682      1.098612  0.000000  0\n",
       "29     0.287682      0.318454  0.000000  0"
      ]
     },
     "execution_count": 67,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data_bin_woe = data.loc[:, ('Age_Bin', 'TaCA_Bin', 'ES', 'y')]\n",
    "def test(x):\n",
    "    print(x)\n",
    "for col in ['Age_Bin', 'TaCA_Bin', 'ES']:\n",
    "    data_bin_woe[col+'_WOE'] = data_bin_woe[col].map(lambda x: df_woe.loc[df_woe['index']==x, 'WOE'].to_list()[0])\n",
    "data_woe = data_bin_woe.loc[:, ('Age_Bin_WOE', 'TaCA_Bin_WOE', 'ES_WOE', 'y')]\n",
    "data_woe"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-05-27T03:55:03.751986Z",
     "start_time": "2019-05-27T03:55:03.740333Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0.5981120241664705, 0.6553198919114246, 0.3129258904273545]\n",
      "[-0.00981552]\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/xusj/anaconda3/lib/python3.7/site-packages/sklearn/linear_model/logistic.py:433: FutureWarning: Default solver will be changed to 'lbfgs' in 0.22. Specify a solver to silence this warning.\n",
      "  FutureWarning)\n"
     ]
    }
   ],
   "source": [
    "clf = LogisticRegression()\n",
    "clf.fit(data_woe.iloc[:, 0:3], data_woe.iloc[:, 3])\n",
    "\n",
    "list_coef = list(clf.coef_[0])\n",
    "intercept = clf.intercept_\n",
    "\n",
    "print(list_coef)\n",
    "print(intercept)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "P0 = 50\n",
    "PDO = 10\n",
    "theta = 0.05\n",
    "\n",
    "B = PDO / np."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
